/*

  These builtin library files are attached to the executable
  at compile time.

  If your .lib file is named:

    basic_debug.lib

  then your namespace in which your functions reside must be:

    basic

  so that the compiler can statically link your initalization
  correctly without colliding with other builtin libraries.

  In the library .lib file, the exported InitializeBuiltins will
  look like:

    ?InitalizeBuiltins@basic@@YAXPAVAdderBytecodeEngine@@@Z
	?InitalizeBuiltins@othernamespace@@YAXPAVAdderBytecodeEngine@@@Z

*/
#include <AdderBytecodeEngine.h>
#include <AdderFunction.h>
#include <AdderObject.h>
#include <AdderString.h>
#include <AdderLibraryMacros.h>
#include <stdio.h>

namespace basic
{
	void ReinitalizeBuiltins(AdderBytecodeEngine* engine);
	AdderValue * print(AdderBytecodeEngine* engine, AdderValue* arg0);
	AdderValue * str(AdderBytecodeEngine* engine, AdderValue* arg0);
	AdderValue * len(AdderBytecodeEngine* engine, AdderValue* arg0);
	AdderValue * list(AdderBytecodeEngine* engine);

	void InitalizeBuiltins(AdderBytecodeEngine* engine)
	{
		// Here we initalize the engine and provide it links to our own
		// builtins that we have defined.
		engine->BuiltinRegisterScopeChange("Basic", &ReinitalizeBuiltins);
		engine->BuiltinRegisterFunction("print", &print);
		engine->BuiltinRegisterFunction("str", &str);
		engine->BuiltinRegisterFunction("len", &len);
		engine->BuiltinRegisterFunction("list", &list);
	}

	void ReinitalizeBuiltins(AdderBytecodeEngine* engine)
	{
		// This function is called when we need to reload the builtin variables
		// because of a scope change.
		//
		// NOTE: You only need to reload the variables here, not classes or
		//       functions.
	}

	AdderValue * print(AdderBytecodeEngine* engine, AdderValue* arg0)
	{
		if (arg0->type == AdderValueType::STRING)
			printf("%s\n", arg0->a_string().c_str());
		else if (arg0->type == AdderValueType::NUMBER)
			printf("%f\n", arg0->r_number);
		else
			// FIXME: 
			printf("<unsupported object>");

		return NULL;
	}

	AdderValue * str(AdderBytecodeEngine* engine, AdderValue* arg0)
	{
		if (arg0->type == AdderValueType::STRING)
		{
			AdderValue * r = new AdderValue();
			r->type = AdderValueType::STRING;
			r->a_string() = arg0->a_string();
			return r;
		}
		else if (arg0->type == AdderValueType::NUMBER)
		{
			// fast conversion
			AdderValue * r = new AdderValue();
			r->type = AdderValueType::STRING;
			char * n = (char*)calloc(_scprintf("%f", arg0->r_number) + 1, sizeof(char));
			sprintf(n, "%f", arg0->r_number);
			r->a_string() = n;
			free(n);
			return r;
		}
		else
		{
			THROW_ERROR_0("<BUILTIN STR>", "Can not convert this type of variable to a string.");
			return NULL;
		}
	}

	AdderValue * len(AdderBytecodeEngine* engine, AdderValue* arg0)
	{
		return NULL;
	}

	AdderValue * list(AdderBytecodeEngine* engine)
	{
		return NULL;
	}
}